from datetime import datetime
import os
import random
import math
import pyautogui
import cv2
import numpy as np
from PIL import ImageGrab

import areaposition


# 新增：临时文件清理函数
def clean_temp_file(file_path):
    """清理临时截图文件"""
    try:
        if os.path.exists(file_path):
            os.remove(file_path)
            _log.info(f"临时文件 {file_path} 已清理")
    except Exception as e:
        _log.error(f"清理临时文件失败：{e}")


# 新增：OpenCV图片转临时文件
def cv2_img_to_temp_file(cv_img):
    """将OpenCV格式图片保存为临时文件，返回文件路径"""
    # 创建临时文件（PNG格式，避免压缩失真）
    temp_fd, temp_path = tempfile.mkstemp(suffix='.png')
    os.close(temp_fd)  # 关闭文件描述符，避免占用

    # 将OpenCV的BGR格式转为RGB并保存
    rgb_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
    pil_img = Image.fromarray(rgb_img)
    pil_img.save(temp_path, format='PNG')

    return temp_path


def ensure_screenshot_dir():
    """确保screenshot文件夹存在，不存在则创建"""
    if not os.path.exists("screenshot"):
        os.makedirs("screenshot")


def capture_save(button):
    """截取屏幕右下角100x100的区域并保存到screenshot文件夹"""
    # 获取屏幕尺寸
    # screen_width, screen_height = pyautogui.size()
    # 计算右下角区域的坐标
    # 确认按钮位置
    left = button.left
    top = button.top
    right = button.right
    bottom = button.bottom

    # 截取指定区域
    screenshot = ImageGrab.grab(bbox=(left, top, right, bottom))
    # 转换为OpenCV格式
    cv_img = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

    # 确保保存目录存在
    ensure_screenshot_dir()
    now = datetime.now()
    # 生成带时间戳的文件名（避免重复）
    timestamp = now.strftime("%Y%m%d_%H%M%S") + f"_{now.microsecond // 1000:03d}"
    save_path = f"screenshot/capture_{timestamp}.jpg"

    # 保存图片
    cv2.imwrite(save_path, cv_img)
    print(f"截图已保存至: {save_path}")

    return cv_img


# 截图
def capture(button):
    """截取屏幕右下角100x100的区域并保存到screenshot文件夹"""
    # 获取屏幕尺寸
    # screen_width, screen_height = pyautogui.size()
    # 计算右下角区域的坐标
    # 确认按钮位置
    left = button.left
    top = button.top
    right = button.right
    bottom = button.bottom

    # 截取指定区域
    screenshot = ImageGrab.grab(bbox=(left, top, right, bottom))
    # 转换为OpenCV格式
    cv_img = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

    # 确保保存目录存在
    ensure_screenshot_dir()
    now = datetime.now()
    # 生成带时间戳的文件名（避免重复）
    timestamp = now.strftime("%Y%m%d_%H%M%S") + f"_{now.microsecond // 1000:03d}"
    save_path = f"screenshot/capture_{timestamp}.jpg"

    # 保存图片
    # cv2.imwrite(save_path, cv_img)
    # print(f"截图已保存至: {save_path}")

    return cv_img


# 将两个图片适当裁剪，使得能够比较
def crop_width_to_fit(large_gray, small_gray):
    """
    优先保留高度，裁剪大图宽度以适配小图宽度（确保宽高均满足匹配条件）
    返回裁剪后的大图和小图
    """
    h_large, w_large = large_gray.shape[:2]
    h_small, w_small = small_gray.shape[:2]

    # 确保高度满足（大图高度 >= 小图高度）
    if h_large < h_small:
        return None, None  # 高度不足，无法裁剪适配

    # 如果宽度已满足，直接返回
    if w_large >= w_small:
        return large_gray, small_gray

    # 宽度不足时，裁剪小图宽度以匹配大图（优先保留小图左侧内容）
    # 注意：这里是裁剪小图（模板）来适配大图，因为模板需要更小
    cropped_small = small_gray[:, 0:w_large]  # 从左侧裁剪小图宽度至大图宽度
    return large_gray, cropped_small


def compare_images_with_color(img1, img2):
    """比较两张图片的相似度（自动处理尺寸不一致问题），返回百分比"""
    # 计算结构相似性指数(SSIM)
    from skimage.metrics import structural_similarity as ssim
    # 处理尺寸不一致
    if img1.shape != img2.shape:
        target_height, target_width = img1.shape[:2]
        img2 = cv2.resize(img2, (target_width, target_height), interpolation=cv2.INTER_LINEAR)

    # 不转灰度，直接在RGB三个通道分别计算SSIM
    ssim_scores = []
    for channel in range(3):  # 遍历R、G、B通道
        channel1 = img1[:, :, channel]
        channel2 = img2[:, :, channel]
        # 计算单通道SSIM（范围[-1,1]）
        score = ssim(channel1, channel2)
        ssim_scores.append(score)

    # 取三通道平均值，转换为百分比
    avg_score = sum(ssim_scores) / 3
    return (avg_score + 1) / 2 * 100


# 比较两个图片的相似程度
def compare_image_in_larger_image(img1, img2):
    """
    优先保留高度，通过裁剪宽度适配尺寸，检测子图匹配度
    """
    # 转换为灰度图
    gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

    # 获取两张图的尺寸 (高, 宽)
    h1, w1 = gray1.shape[:2]
    h2, w2 = gray2.shape[:2]

    # 确定初始大图和小图（先按高度判断）
    if h1 >= h2:
        candidate_large = gray1
        candidate_small = gray2
    else:
        candidate_large = gray2
        candidate_small = gray1

    # 裁剪宽度以适配（优先保留高度）
    large_gray, small_gray = crop_width_to_fit(candidate_large, candidate_small)
    if large_gray is None or small_gray is None:
        print("警告：高度不匹配且无法通过裁剪宽度适配")
        return 0.0

    # 确保裁剪后小图尺寸有效
    h_small_final, w_small_final = small_gray.shape[:2]
    if h_small_final == 0 or w_small_final == 0:
        print("警告：裁剪后小图尺寸无效")
        return 0.0

    # 执行模板匹配
    result = cv2.matchTemplate(large_gray, small_gray, cv2.TM_CCOEFF_NORMED)
    max_val = np.max(result)  # 最高匹配值（范围[-1, 1]）

    return max_val * 100


# 生成曲线路径点
def bezier_curve(points, num_steps):
    """生成贝塞尔曲线路径点"""
    n = len(points) - 1

    def bezier(t):
        x = 0.0
        y = 0.0
        for i in range(n + 1):
            binomial = math.comb(n, i)
            term = binomial * (t ** i) * ((1 - t) ** (n - i))
            x += term * points[i][0]
            y += term * points[i][1]
        return (x, y)

    return [bezier(t / num_steps) for t in range(num_steps + 1)]


# 平滑带抖动的鼠标移动（基于贝塞尔曲线）
def smooth_move_with_jitter(target_x, target_y, duration=0.15, jitter_strength=1.2, min_steps=3):
    """
    更快的平滑带抖动鼠标移动
    :param duration: 总时长（秒），默认0.15秒（比原来的0.2更短）
    :param jitter_strength: 抖动强度（适当减小，避免影响速度）
    :param min_steps: 最小步数（减少步数加快速度）
    """
    screen_width, screen_height = pyautogui.size()
    corner_threshold = 50  # 角落安全阈值

    # 判断坐标是否安全（远离角落）
    def is_safe(x, y):
        return not (
                (x <= corner_threshold and y <= corner_threshold) or
                (x >= screen_width - corner_threshold and y <= corner_threshold) or
                (x <= corner_threshold and y >= screen_height - corner_threshold) or
                (x >= screen_width - corner_threshold and y >= screen_height - corner_threshold)
        )

    # 目标坐标不安全则移到屏幕中间
    if not is_safe(target_x, target_y):
        target_x = screen_width // 2
        target_y = screen_height // 2

    start_x, start_y = pyautogui.position()

    # 生成更紧凑的控制点（减少路径弯曲，加快速度）
    control_x = start_x + random.uniform(
        -abs(target_x - start_x) * 0.2,  # 控制范围从0.3缩小到0.2
        abs(target_x - start_x) * 0.2
    )
    control_y = start_y + random.uniform(
        -abs(target_y - start_y) * 0.2,
        abs(target_y - start_y) * 0.2
    )
    # 确保控制点安全
    if not is_safe(control_x, control_y):
        control_x = max(corner_threshold, min(control_x, screen_width - corner_threshold))
        control_y = max(corner_threshold, min(control_y, screen_height - corner_threshold))

    control_points = [(start_x, start_y), (control_x, control_y), (target_x, target_y)]

    # 减少步数（每20ms一步，比原来的15ms更疏）
    num_steps = int(duration * 1000 / 20)  # 步数 = 总时长(毫秒) / 步间隔(毫秒)
    num_steps = max(min_steps, num_steps)  # 确保至少有最小步数

    # 生成路径
    path = bezier_curve(control_points, num_steps)

    # 快速移动（缩短每步的duration）
    for i, (x, y) in enumerate(path):
        # 过滤不安全的中间点
        if not is_safe(x, y):
            x = max(corner_threshold, min(x, screen_width - corner_threshold))
            y = max(corner_threshold, min(y, screen_height - corner_threshold))

        progress = i / num_steps
        jitter_factor = (1 - abs(progress - 0.5) * 2) * jitter_strength
        jitter_x = random.gauss(0, jitter_factor)
        jitter_y = random.gauss(0, jitter_factor)

        # 最终坐标安全检查
        final_x = round(x + jitter_x)
        final_y = round(y + jitter_y)
        final_x = max(corner_threshold, min(final_x, screen_width - corner_threshold))
        final_y = max(corner_threshold, min(final_y, screen_height - corner_threshold))

        # 每步移动时长缩短到0.005秒（原来0.01秒）
        pyautogui.moveTo(final_x, final_y, duration=0.005)

    # 最终定位（快速精准移动）
    final_target_x = max(corner_threshold, min(target_x, screen_width - corner_threshold))
    final_target_y = max(corner_threshold, min(target_y, screen_height - corner_threshold))
    pyautogui.moveTo(final_target_x, final_target_y, duration=0.01)  # 缩短最终移动时长


def move_to_and_click(x, y):
    smooth_move_with_jitter(x, y, duration=0.15, jitter_strength=1.2)
    pyautogui.click()


def move_to_free_area():
    free_area = areaposition.free_area
    # 生成 x 随机数（free_area.left 到 free_area.right 之间的整数，包含两端）
    x = random.randint(free_area.left, free_area.right)

    # 生成 y 随机数（free_area.top 到 free_area.bottom 之间的整数，包含两端）
    y = random.randint(free_area.top, free_area.bottom)
    # pyautogui.moveTo(x, y, duration=0.2)
    smooth_move_with_jitter(x, y, duration=0.1, jitter_strength=1.2)
